﻿// Owner: wangwj-f
// Co-Owner:liuj-av

#include "VisualUiViewMouseEventHandler.h"
#include "IUiViewMouseEventArgs.h"
#include "IApplication.h"
#include "IMainWindow.h"
#include "IStatusBar.h"
#include "IStatusBarPanel.h"
#include "IControl.h"
#include "IControlDefinition.h"
#include "ILabelDefinition.h"
#include "IPickCandidates.h"
#include "IPick.h"
#include "IGraphicsNodeReference.h"
#include "IElementBasicInformation.h"
#include "IDocument.h"
#include "IElement.h"
#include "ICategory.h"
#include "ICategoryLibrary.h"
#include "IInstanceType.h"
#include "IFamily.h"
#include "IUiDocument.h"
#include "IUiDocumentViewManager.h"
#include "Vector3d.h"
#include "StringUtil.h"
#include "DebugMessage.h"
#include "DebugMessage.h"
#include "ICamera.h"
#include "IUiView.h"
#include "IUserTransaction.h"
#include "UiDocumentViewUtils.h"
#include "Vector3dUtils.h"
#include "UiViewUtils.h"
#include "IPointPickContext.h"
#include "IPickResult.h"
#include "IPicker.h"
#include "ILine3d.h"
#include "Vector2dUtils.h"
#include "ICanvas.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
#include "IModelView.h"
#include "GraphicsNodeUtils.h"
#include "IGraphicsElementShape.h"
#include "Box3d.h"
#include "IPlane.h"
#include "AlgorithmIntersect.h"

using namespace gcmp;
using namespace Sample;

//*------------------------------------------------------------------*/
// 描述：鼠标移动的反应器
//*------------------------------------------------------------------*/
void VisualUiViewMouseEventHandler::On(IUiViewMouseEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs,L"pArgs为空", L"GDMP", L"2020/09/21");
    IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument指针为空", L"GDMP", L"2022.12.01");
    IUiView* pUiView = UiDocumentViewUtils::GetCurrentUiView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiView, L"pUiView为空", L"GDMP", L"2022.12.01");
    Vector3d pt = pArgs->GetMousePosition();
    UiViewMouseEventType nType = pArgs->GetType();

    if (nType == UiViewMouseEventType::LeftButtonDown)
    {
        CalculateRotateCenter(pt);
        m_bMouseLeftButtonDown = true;

        int nX(0), nY(0);
        float fDepth = 0.0f;
        UiViewUtility::WorldPositionToScreenPosition(pUiView, pt, nX, nY, fDepth);
        m_ptBefore.Set(nX, nY);
    }
    else if (nType == UiViewMouseEventType::RightButtonDown)
    {
        m_bMouseRightButtonDown = true;

        int nX(0), nY(0);
        float fDepth = 0.0f;
        UiViewUtility::WorldPositionToScreenPosition(pUiView, pt, nX, nY, fDepth);
        m_ptBefore.Set(nX, nY);
    }
    if (nType == UiViewMouseEventType::RightButtonUp)
    {
        m_bMouseRightButtonDown = false; 
    }
    else if (m_bMouseRightButtonDown && nType == UiViewMouseEventType::Move)
    {
        LookUtils(pArgs->GetMousePosition(), LookType::LookAround);
    }
    else if (nType == UiViewMouseEventType::LeftButtonUp)
    {
        m_bMouseLeftButtonDown = false;
    }
    else if (m_bMouseLeftButtonDown && nType == UiViewMouseEventType::Move)
    {
        LookUtils(pArgs->GetMousePosition(), LookType::CameraRotate);
    }
}

void Sample::VisualUiViewMouseEventHandler::LookUtils(const gcmp::Vector3d & pt, LookType lookType)
{
    IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument指针为空", L"GDMP", L"2020-03-22");

    IUiView* pUiView = UiDocumentViewUtils::GetCurrentUiView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiView, L"pUiView为空", L"GDMP", L"2020/06/10");

    int nWidth = pUiView->GetWindowWidth();
    int nHeight = pUiView->GetWindowHeight();
    if (nWidth == 0 || nHeight == 0)
    {
        return;
    }

    // 获取相机
    ICanvas *pCanvas = pUiView->GetCanvas();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCanvas, L"pCanvas为空", L"GDMP", L"2021-02-22");
    ICamera* pCamera = pCanvas->GetCamera();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCamera, L"pCamera为空", L"GDMP", L"2020/06/10");

    CameraType type = CameraType::Perspective;
    Vector3d position;
    Vector3d direction;
    Vector3d upDirection;
    double aspectRatio = 0.0;
    double nearDist = 0.0;
    double farDist = 0.0;
    double fieldOfView = 0.0;
    double orthoWindowHeight = 0.0;
    pCamera->GetAllParameters(type,
        position, direction, upDirection,
        aspectRatio, nearDist, farDist,
        fieldOfView,
        orthoWindowHeight);
    pCamera->GetAllParameters(type, position, direction, upDirection, aspectRatio, nearDist, farDist, fieldOfView, orthoWindowHeight);

    int nX(0), nY(0);
    float fDepth = 0.0f;
    UiViewUtility::WorldPositionToScreenPosition(pUiView, pt, nX, nY, fDepth);
    gcmp::Vector2d ptMove(nX, nY);
    gcmp::Vector2d vX(1, 0), vY(0, 1);
    gcmp::Vector2d vMove = ptMove - m_ptBefore;

    double dLenMove = vMove.Length();
    if (MathUtils::IsZero(dLenMove))
    {
        return;
    }

    double dDotX = vMove.Dot(vX);
    double dDotY = vMove.Dot(vY);

    // 顶视图和底视图，则不作环视
    const Vector3d vTop(0, 0, -1);
    const Vector3d vBottom(0, 0, 1);
    if (direction == vTop || direction == vBottom)
    {
        double dAng = -1.0 * dDotX / nWidth * Constants::MATH_2PI;
        upDirection = Vector3dUtils::RotateVectorAroundAxis(upDirection, direction, dAng);
    }
    else
    {
        // 防止把地平面旋转起来
        upDirection.SetX(0);
        upDirection.SetY(0);

        // LR
        double dLRAng = -1.0 * dDotX / nWidth * Constants::MATH_2PI;
        direction = Vector3dUtils::RotateVectorAroundAxis(direction, upDirection, dLRAng);

        // UD
        double dUDAng = -1.0 * dDotY / nHeight * (Constants::MATH_PI - 1);
        Vector3d vRoate = direction.Cross(upDirection);
        direction = Vector3dUtils::RotateVectorAroundAxis(direction, vRoate, dUDAng);
        upDirection = Vector3dUtils::RotateVectorAroundAxis(upDirection, vRoate, dUDAng);

        if (upDirection.Z() < 0)
        {
            upDirection = -upDirection;
        }

        if (lookType == LookType::CameraRotate)
        {
            Matrix4d matrixRl;
            matrixRl.MakeRotate(m_rotateCenter, vRoate, dUDAng);
            Matrix4d matrixDl;
            matrixDl.MakeRotate(m_rotateCenter, upDirection, dLRAng);
            Matrix4d matrix = matrixRl * matrixDl;
            position = Matrix4dUtils::PointMultiplyMatrix(position, matrix);
        }
    }
    pCamera->SetAllParameters(type, position,
        direction, upDirection,
        aspectRatio, nearDist,
        farDist, fieldOfView,
        orthoWindowHeight);

    m_ptBefore = ptMove;
}

void VisualUiViewMouseEventHandler::CalculateRotateCenter(Vector3d mousePt)
{
    IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument指针为空", L"GDMP", L"2020-03-22");

    IUiView* pUiView = UiDocumentViewUtils::GetCurrentUiView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiView, L"pUiView为空", L"GDMP", L"2020/06/10");

    // 获取相机
    ICanvas *pCanvas = pUiView->GetCanvas();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCanvas, L"pCanvas为空", L"GDMP", L"2021-02-22");
    ICamera* pCamera = pCanvas->GetCamera();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCamera, L"pCamera为空", L"GDMP", L"2020/06/10");

    IModelView *pModelView = pCanvas->GetModelView();
    Box3d mergedBox = Box3d::CreateEmptyBox3d();
    const GraphicsElementShapes& greps = pModelView->GetVisibleModelViewElementShapes();
    FOR_EACH(wpGrep, greps)
    {
        const IGraphicsElementShape* pGrep = wpGrep.second.Get();
        if (!pGrep || pGrep->GetChildrenCount() <= 0 || pGrep->GetBox().IsEmpty())
        {
            continue;
        }
        Box3d grepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDocument, pGrep);
        mergedBox.MergeBox(grepBox);
    }

    Vector3d boxCenter = mergedBox.GetCenter();

    OwnerPtr<IPlane> opPlane = IPlane::Create(boxCenter, pCamera->GetDirection());
    OwnerPtr<ILine3d> opLine = ILine3d::Create(mousePt, pCamera->GetDirection() * Constants::MAX_MODEL_SPACE_SIZE);
    AlgorithmIntersect::Intersect(opLine.get(), opPlane.get(), m_rotateCenter);
}

